"""
@author: 江同学呀
@file: term_level_queries.py
@date: 2025/1/8 23:36
@desc:
    术语级查询
    https://www.elastic.co/guide/en/elasticsearch/reference/7.17/term-level-queries.html

    You can use term-level queries to find documents based on precise values in structured data. Examples of structured
    data include date ranges, IP addresses, prices, or product IDs.
    Unlike full-text queries, term-level queries do not analyze search terms. Instead, term-level queries match the
    exact terms stored in a field.
    Term-level queries still normalize search terms for keyword fields with the normalizer property. For more details,
    see normalizer.

    您可以使用字词级查询根据结构化数据中的精确值查找文档。结构化数据的示例包括日期范围、IP 地址、价格或产品 ID。
    与全文查询不同，术语级查询不分析搜索词。相反，术语级查询与字段中存储的确切术语匹配。
    术语级查询仍使用 normalizer 属性规范化关键字字段的搜索词。有关更多详细信息，请参阅 normalizer。
"""
from typing import Union, Dict, List, Literal, Iterable

from espc.common.common import Number
from espc.common.query_common import RangeRelation, Rewrite
from espc.err.err import ESPCParamsError
from espc.orm.model.dsl.queries.base_queries import _BaseQueries
from espc.orm.model.mapping.field.base_field.base_field import _BaseField
from espc.orm.model.model.base_index import BaseIndex


class Exist(_BaseQueries):
    """
    存在查询
    https://www.elastic.co/guide/en/elasticsearch/reference/7.17/query-dsl-exists-query.html

    Returns documents that contain an indexed value for a field.
    An indexed value may not exist for a document’s field due to a variety of reasons:
        - The field in the source JSON is null or []
        - The field has "index" : false set in the mapping
        - The length of the field value exceeded an ignore_above setting in the mapping
        - The field value was malformed and ignore_malformed was defined in the mapping

    返回包含字段的索引值的文档。
    由于各种原因，文档的字段可能不存在索引值：
        - 源 JSON 中的字段为 null 或 []
        - 字段在映射中设置了 “index” ： false
        - 字段值的长度超出了映射中的 ignore_above 设置
        - 字段值格式错误，并且ignore_malformed在映射中定义

    :param field: 字段名
        (Required, string) Name of the field you wish to search.
        While a field is deemed non-existent if the JSON value is null or [], these values will indicate the field does exist:
        Empty strings, such as "" or "-"
        Arrays containing null and another value, such as [null, "foo"]
        A custom null-value, defined in field mapping

        （必需，字符串）要搜索的字段的名称。
        如果 JSON 值为 null 或 []，则字段被视为不存在，但这些值将指示该字段确实存在：
        空字符串，例如 “” 或 “-”
        包含 null 和其他值的数组，例如 [null， “foo”]
        在字段映射中定义的自定义 null 值
    """
    type: str = "exist"

    def __init__(self, field: Union[str, _BaseField]):
        super().__init__()
        self._field: Union[str, _BaseField] = field
        return

    def _build(self) -> Dict:
        return {
            "field": self._field if isinstance(self._field, str) else self._field._field_name
        }


class Fuzzy(_BaseQueries):
    """
    模糊查询
    https://www.elastic.co/guide/en/elasticsearch/reference/7.17/query-dsl-fuzzy-query.html

    Returns documents that contain terms similar to the search term, as measured by a Levenshtein edit distance.
    An edit distance is the number of one-character changes needed to turn one term into another. These changes can include:
        - Changing a character (box → fox)
        - Removing a character (black → lack)
        - Inserting a character (sic → sick)
        - Transposing two adjacent characters (act → cat)
    To find similar terms, the fuzzy query creates a set of all possible variations, or expansions, of the search term
    within a specified edit distance. The query then returns exact matches for each expansion.

    返回包含与搜索词相似的检索词（由 Levenshtein 编辑距离测量）的文档。
    编辑距离是将一个术语转换为另一个术语所需的单字符更改次数。这些更改可能包括：
        - 更改字符 （box → fox）
        - 删除字符 （black → lack）
        - 插入字符 （sic →sic k）
        - 转置两个相邻字符 （act → cat）
    为了查找相似的词，模糊查询会在指定的编辑距离内创建搜索词的所有可能变体或扩展的集合。然后，该查询返回每个扩展的完全匹配项。

    :param field:
        (Required, object) Field you wish to search.
        （必需，对象）要搜索的字段。
    :param value:
        (Required, string) Term you wish to find in the provided <field>.
        （必需，字符串）您希望在提供的 <field> 中找到的术语。
    :param fuzziness:
        (Optional, string) Maximum edit distance allowed for matching. See Fuzziness for valid values and more information.
        （可选，字符串）允许匹配的最大编辑距离。请参阅 Fuzziness 了解有效值和更多信息。
    :param max_expansions:
        (Optional, integer) Maximum number of variations created. Defaults to 50.
        （可选，整数）创建的最大变体数。默认值为 50。
    :param prefix_length:
        (Optional, integer) Number of beginning characters left unchanged when creating expansions. Defaults to 0.
        （可选，整数）创建扩展时保持不变的开始字符数。默认为 0。
    :param transpositions:
        (Optional, Boolean) Indicates whether edits include transpositions of two adjacent characters (ab → ba). Defaults to true.
        （可选，布尔值）指示编辑是否包括两个相邻字符 （ab → ba） 的移调。默认为 true。
    :param rewrite:
        (Optional, string) Method used to rewrite the query. For valid values and more information, see the rewrite parameter.
        （可选，字符串）用于重写查询的方法。有关有效值和更多信息，请参阅 rewrite 参数。
    """
    type: str = "fuzzy"

    def __init__(
            self, field: Union[str, _BaseField], value: str, fuzziness: str = None,
            max_expansions: int = None, prefix_length: int = None, transpositions: bool = None,
            rewrite: Union[
                Literal[
                    "constant_score", "constant_score_boolean", "scoring_boolean", "top_terms_blended_freqs_N",
                    "top_terms_boost_N", "top_terms_N"
                ],
                Rewrite
            ] = None
    ):
        super().__init__()
        self._field: Union[str, _BaseField] = field
        self._value: str = value
        self._fuzziness: str = fuzziness
        self._max_expansions: int = max_expansions
        self._prefix_length: int = prefix_length
        self._transpositions: bool = transpositions
        self._rewrite: Union[
            Literal[
                "constant_score", "constant_score_boolean", "scoring_boolean", "top_terms_blended_freqs_N",
                "top_terms_boost_N", "top_terms_N"
            ], Rewrite, None
        ] = rewrite
        return

    def _build(self) -> Dict:
        _body: Dict = {
            "value": self._value,
        }
        if self._fuzziness:
            _body["fuzziness"] = self._fuzziness
        if self._max_expansions is not None:
            _body["max_expansions"] = self._max_expansions
        if self._prefix_length is not None:
            _body["prefix_length"] = self._prefix_length
        if self._transpositions is not None:
            _body["transpositions"] = self._transpositions
        if self._rewrite:
            _body["rewrite"] = self._rewrite if isinstance(self._rewrite, str) else self._rewrite.value
        return {
            self._field if isinstance(self._field, str) else self._field._field_name: _body
        }


class Ids(_BaseQueries):
    """
    id查询
    https://www.elastic.co/guide/en/elasticsearch/reference/7.17/query-dsl-ids-query.html

    Returns documents based on their IDs. This query uses document IDs stored in the _id field.
    根据文档的 ID 返回文档。此查询使用存储在 _id 字段中的文档 ID。

    :param values:
        (Required, array of strings) An array of document IDs.
        （必需，字符串数组）文档 ID 数组。
    """
    type: str = "ids"

    def __init__(self, values: List[str]):
        super().__init__()
        self._values: List[str] = values
        return

    def _build(self) -> Dict:
        return {
            "values": self._values
        }


class Prefix(_BaseQueries):
    """
    前缀查询
    https://www.elastic.co/guide/en/elasticsearch/reference/7.17/query-dsl-prefix-query.html

    Returns documents that contain a specific prefix in a provided field.
    返回在提供的字段中包含特定前缀的文档。

    :param field:
        (Required, object) Field you wish to search.
        （必需，对象）要搜索的字段。
    :param value:
        (Required, string) Beginning characters of terms you wish to find in the provided <field>.
        （必需，字符串）您希望在提供的 <字段中找到的术语的开始字符>。
    :param rewrite:
        (Optional, string) Method used to rewrite the query. For valid values and more information, see the rewrite parameter.
        （可选，字符串）用于重写查询的方法。有关有效值和更多信息，请参阅 rewrite 参数。
    :param case_insensitive:
        (Optional, Boolean) Allows ASCII case insensitive matching of the value with the indexed field values when
        set to true. Default is false which means the case sensitivity of matching depends on the underlying field’s
        mapping.
        （可选，布尔值）当设置为 true 时，允许将值与索引字段值进行 ASCII 不区分大小写的匹配。默认值为 false，这意味着匹配的区分大小写取决于
        基础字段的映射。
    """
    type: str = "prefix"

    def __init__(
            self, field: Union[str, _BaseField], value: str,
            rewrite: Union[
                Literal[
                    "constant_score", "constant_score_boolean", "scoring_boolean", "top_terms_blended_freqs_N",
                    "top_terms_boost_N", "top_terms_N"
                ],
                Rewrite
            ] = None,
            case_insensitive: bool = None
    ):
        super().__init__()
        self._field: Union[str, _BaseField] = field
        self._value: str = value
        self._rewrite: Union[
            Literal[
                "constant_score", "constant_score_boolean", "scoring_boolean", "top_terms_blended_freqs_N",
                "top_terms_boost_N", "top_terms_N"
            ], Rewrite, None
        ] = rewrite
        self._case_insensitive: bool = case_insensitive
        return

    def _build(self) -> Dict:
        _body: Dict = {
            "value": self._value,
        }
        if self._case_insensitive is not None:
            _body["case_insensitive"] = self._case_insensitive
        if self._rewrite:
            _body["rewrite"] = self._rewrite if isinstance(self._rewrite, str) else self._rewrite.value
        return {
            self._field if isinstance(self._field, str) else self._field._field_name: _body
        }


class Range(_BaseQueries):
    """
    范围查询
    https://www.elastic.co/guide/en/elasticsearch/reference/7.17/query-dsl-range-query.html

    Returns documents that contain terms within a provided range.
    返回包含所提供范围内的术语的文档。

    :param field:
        (Required, object) Field you wish to search.
        （必需，对象）要搜索的字段。
    :param gt:
        (Optional) Greater than.
        （可选）大于。
    :param gte:
        (Optional) Greater than or equal to.
        （可选）大于或等于。
    :param lt:
        (Optional) Less than.
        （可选）小于。
    :param lte:
        (Optional) Less than or equal to.
        （可选）小于或等于。
    :param format_:
        (Optional, string) Date format used to convert date values in the query.
        By default, Elasticsearch uses the date format provided in the <field>'s mapping. This value overrides that
        mapping format.
        For valid syntax, see format.

        （可选，字符串）用于转换查询中的日期值的日期格式。
        默认情况下，Elasticsearch 使用 <field> 映射中提供的日期格式。此值将覆盖该映射格式。
        有关有效的语法，请参阅 格式。
    :param relation:
        (Optional, string) Indicates how the range query matches values for range fields. Valid values are:
            - INTERSECTS (Default)
                Matches documents with a range field value that intersects the query’s range.
            - CONTAINS
                Matches documents with a range field value that entirely contains the query’s range.
            - WITHIN
                Matches documents with a range field value entirely within the query’s range.

        （可选，字符串）指示范围查询如何匹配范围字段的值。有效值为：
            - INTERSECTS （默认）
                将文档与与查询范围相交的范围字段值匹配。
            - CONTAINS
                将文档与完全包含查询范围的 range 字段值匹配。
            - WITHIN
                匹配 range 字段值完全在查询范围内的文档。
    :param time_zone:
        (Optional, string) Coordinated Universal Time (UTC) offset or IANA time zone used to convert date values in the
        query to UTC.
        Valid values are ISO 8601 UTC offsets, such as +01:00 or -08:00, and IANA time zone IDs, such as
        America/Los_Angeles.
        For an example query using the time_zone parameter, see Time zone in range queries.

        （可选，字符串）用于将查询中的日期值转换为 UTC 的协调世界时 （UTC） 偏移量或 IANA 时区。
        有效值为 ISO 8601 UTC 偏移量（例如 +01：00 或 -08：00）和 IANA 时区 ID（例如 America/Los_Angeles）。
        有关使用 time_zone 参数的示例查询，请参阅范围查询中的时区。
    :param boost:
        (Optional, float) Floating point number used to decrease or increase the relevance scores of a query.
        Defaults to 1.0.
        You can use the boost parameter to adjust relevance scores for searches containing two or more queries.
        Boost values are relative to the default value of 1.0. A boost value between 0 and 1.0 decreases the relevance
        score. A value greater than 1.0 increases the relevance score.

        （可选，浮点数）用于降低或提高查询相关性分数的浮点数。默认为 1.0。
        您可以使用 boost 参数来调整包含两个或多个查询的搜索的相关性得分。
        提升值是相对于默认值 1.0 的。介于 0 和 1.0 之间的提升值会降低相关性分数。大于 1.0 的值会增加相关性分数。
    """
    type: str = "range"

    def __init__(
            self, field: Union[str, _BaseField], gt: Union[str, Number] = None,
            gte: Union[str, Number] = None, lt: Union[str, Number] = None, lte: Union[str, Number] = None,
            format_: str = None, relation: Union[Literal["INTERSECTS", "CONTAINS", "WITHIN"], RangeRelation] = None,
            time_zone: str = None, boost: float = None,
    ):
        super().__init__()
        self._field: Union[str, _BaseField] = field
        self._gt: Union[str, Number] = gt
        self._gte: Union[str, Number] = gte
        self._lt: Union[str, Number] = lt
        self._lte: Union[str, Number] = lte
        self._format_: str = format_
        self._relation: Union[Literal["INTERSECTS", "CONTAINS", "WITHIN"], RangeRelation, None] = relation
        self._time_zone: str = time_zone
        self._boost: float = boost
        return

    def _build(self) -> Dict:
        _body: Dict = {}
        if self._gt is not None:
            _body["gt"] = self._gt
        if self._gte is not None:
            _body["gte"] = self._gte
        if self._lt is not None:
            _body["lt"] = self._lt
        if self._lte is not None:
            _body["lte"] = self._lte
        if self._format_ is not None:
            _body["format"] = self._format_
        if self._relation is not None:
            _body["relation"] = self._relation if isinstance(self._relation, str) else self._relation.value
        if self._time_zone is not None:
            _body["time_zone"] = self._time_zone
        if self._boost is not None:
            _body["boost"] = self._boost
        return {
            self._field if isinstance(self._field, str) else self._field._field_name: _body
        }


class Regexp(_BaseQueries):
    """
    正则表达式查询
    https://www.elastic.co/guide/en/elasticsearch/reference/7.17/query-dsl-regexp-query.html

    Returns documents that contain terms matching a regular expression.
    A regular expression is a way to match patterns in data using placeholder characters, called operators. For a list
    of operators supported by the regexp query, see Regular expression syntax.

    返回包含与正则表达式匹配的术语的文档。
    正则表达式是一种使用占位符字符（称为运算符）匹配数据模式的方法。有关 regexp 查询支持的运算符列表，请参阅正则表达式语法。

    :param field:
        (Required, object) Field you wish to search.
        （必需，对象）要搜索的字段。
    :param value:
        (Required, string) Regular expression for terms you wish to find in the provided <field>. For a list of
        supported operators, see Regular expression syntax.
        By default, regular expressions are limited to 1,000 characters. You can change this limit using the
        index.max_regex_length setting.

        （必需，字符串）您希望在提供的 <field> 中找到的术语的正则表达式。有关支持的运算符的列表，请参阅正则表达式语法。
        默认情况下，正则表达式限制为 1000 个字符。您可以使用 index.max_regex_length 设置更改此限制。
    :param flags:
        (Optional, string) Enables optional operators for the regular expression. For valid values and more information,
         see Regular expression syntax.
        （可选，字符串）为正则表达式启用可选运算符。有关有效值和更多信息，请参阅正则表达式语法。
    :param case_insensitive:
        (Optional, Boolean) Allows case insensitive matching of the regular expression value with the indexed field
        values when set to true. Default is false which means the case sensitivity of matching depends on the
        underlying field’s mapping.
        （可选，布尔值）当设置为 true 时，允许正则表达式值与索引字段值进行不区分大小写的匹配。默认值为 false，这意味着匹配的区分大小写取决于基础字段的映射。
    :param max_determinized_states:
        (Optional, integer) Maximum number of automaton states required for the query. Default is 10000.
        Elasticsearch uses Apache Lucene internally to parse regular expressions. Lucene converts each regular
        expression to a finite automaton containing a number of determinized states.
        You can use this parameter to prevent that conversion from unintentionally consuming too many resources. You
        may need to increase this limit to run complex regular expressions.

        （可选，整数）查询所需的最大自动机状态数。默认值为 10000。
        Elasticsearch 在内部使用 Apache Lucene 来解析正则表达式。Lucene 将每个正则表达式转换为包含许多确定状态的有限自动机。
        您可以使用此参数来防止该转换无意中消耗过多资源。您可能需要增加此限制才能运行复杂的正则表达式。
    :param rewrite:
        (Optional, string) Method used to rewrite the query. For valid values and more information, see the rewrite
        parameter.
        （可选，字符串）用于重写查询的方法。有关有效值和更多信息，请参阅 rewrite 参数。
    """
    type: str = "regexp"

    def __init__(
            self, field: Union[str, _BaseField], value: str, flags: str = None,
            case_insensitive: bool = None, max_determinized_states: int = None,
            rewrite: Union[
                Literal[
                    "constant_score", "constant_score_boolean", "scoring_boolean", "top_terms_blended_freqs_N",
                    "top_terms_boost_N", "top_terms_N"
                ],
                Rewrite
            ] = None
    ):
        super().__init__()
        self._field: Union[str, _BaseField] = field
        self._value: str = value
        self._flags: str = flags
        self._case_insensitive: bool = case_insensitive
        self._max_determinized_states: int = max_determinized_states
        self._rewrite: Union[
            Literal[
                "constant_score", "constant_score_boolean", "scoring_boolean", "top_terms_blended_freqs_N",
                "top_terms_boost_N", "top_terms_N"
            ], Rewrite, None
        ] = rewrite
        return

    def _build(self) -> Dict:
        _body: Dict = {
            "value": self._value,
        }
        if self._flags:
            _body["flags"] = self._flags
        if self._case_insensitive is not None:
            _body["case_insensitive"] = self._case_insensitive
        if self._max_determinized_states is not None:
            _body["max_determinized_states"] = self._max_determinized_states
        if self._rewrite:
            _body["rewrite"] = self._rewrite if isinstance(self._rewrite, str) else self._rewrite.value
        return {
            self._field if isinstance(self._field, str) else self._field._field_name: _body
        }


class Term(_BaseQueries):
    """
    术语查询
    https://www.elastic.co/guide/en/elasticsearch/reference/7.17/query-dsl-term-query.html

    Returns documents that contain an exact term in a provided field.
    You can use the term query to find documents based on a precise value such as a price, a product ID, or a username.

    返回在提供的字段中包含确切术语的文档。
    您可以使用术语 query 根据精确值（如价格、产品 ID 或用户名）查找文档。

    :param field:
        (Required, object) Field you wish to search.
        （必需，对象）要搜索的字段。
    :param value:
        (Required, string) Term you wish to find in the provided <field>. To return a document, the term must exactly
        match the field value, including whitespace and capitalization.
        （必需，字符串）您希望在提供的 <field> 中找到的术语。要返回文档，术语必须与字段值完全匹配，包括空格和大写。
    :param boost:
        (Optional, float) Floating point number used to decrease or increase the relevance scores of a query.
        Defaults to 1.0.
        You can use the boost parameter to adjust relevance scores for searches containing two or more queries.
        Boost values are relative to the default value of 1.0. A boost value between 0 and 1.0 decreases the relevance
        score. A value greater than 1.0 increases the relevance score.

        （可选，浮点数）用于降低或提高查询相关性分数的浮点数。默认为 1.0。
        您可以使用 boost 参数来调整包含两个或多个查询的搜索的相关性得分。
        提升值是相对于默认值 1.0 的。介于 0 和 1.0 之间的提升值会降低相关性分数。大于 1.0 的值会增加相关性分数。
    :param case_insensitive:
        (Optional, Boolean) Allows ASCII case insensitive matching of the value with the indexed field values when
        set to true. Default is false which means the case sensitivity of matching depends on the underlying
        field’s mapping.
        （可选，布尔值）当设置为 true 时，允许将值与索引字段值进行 ASCII 不区分大小写的匹配。默认值为 false，这意味着匹配的区分大小写取决于基础字段的映射。
    :param value:
    :param value:
    """
    type: str = "term"

    def __init__(
            self, field: Union[str, _BaseField], value: Union[str, Number], boost: float = None,
            case_insensitive: bool = None
    ):
        super().__init__()
        self._field: Union[str, _BaseField] = field
        self._value: Union[str, Number] = value
        self._boost: float = boost
        self._case_insensitive: bool = case_insensitive
        return

    def _build(self) -> Dict:
        _body: Dict = {
            "value": self._value,
        }
        if self._boost is not None:
            _body["boost"] = self._boost
        if self._case_insensitive is not None:
            _body["case_insensitive"] = self._case_insensitive
        return {
            self._field if isinstance(self._field, str) else self._field._field_name: _body
        }


class Terms(_BaseQueries):
    """
    术语查询
    https://www.elastic.co/guide/en/elasticsearch/reference/7.17/query-dsl-terms-query.html

    Returns documents that contain one or more exact terms in a provided field.
    The terms query is the same as the term query, except you can search for multiple values.

    返回在提供的字段中包含一个或多个精确术语的文档。
    terms 查询与 term query 相同，只是您可以搜索多个值。

    :param field:
        (Optional, object) Field you wish to search.
        The value of this parameter is an array of terms you wish to find in the provided field. To return a document,
        one or more terms must exactly match a field value, including whitespace and capitalization.
        By default, Elasticsearch limits the terms query to a maximum of 65,536 terms. You can change this limit using
        the index.max_terms_count setting.

        （可选，对象）要搜索的字段。
        此参数的值是您希望在提供的字段中找到的术语数组。要返回文档，一个或多个术语必须与字段值完全匹配，包括空格和大写。
        默认情况下，Elasticsearch 将 terms 查询限制为最多 65536 个术语。您可以使用 index.max_terms_count 设置更改此限制。
    :param boost:
        (Optional, float) Floating point number used to decrease or increase the relevance scores of a query.
        Defaults to 1.0.
        You can use the boost parameter to adjust relevance scores for searches containing two or more queries.
        Boost values are relative to the default value of 1.0. A boost value between 0 and 1.0 decreases the relevance
        score. A value greater than 1.0 increases the relevance score.

        （可选，浮点数）用于降低或提高查询相关性分数的浮点数。默认为 1.0。
        您可以使用 boost 参数来调整包含两个或多个查询的搜索的相关性得分。
        提升值是相对于默认值 1.0 的。介于 0 和 1.0 之间的提升值会降低相关性分数。大于 1.0 的值会增加相关性分数。
    :param index:
        (Required, string) Name of the index from which to fetch field values.
        （必需，字符串）要从中获取字段值的索引的名称。
    :param id_:
        (Required, string) ID of the document from which to fetch field values.
        （必需，字符串）要从中获取字段值的文档的 ID。
    :param path:
        (Required, string) Name of the field from which to fetch field values. Elasticsearch uses these values as
        search terms for the query.
        If the field values include an array of nested inner objects, you can access those objects using dot notation
        syntax.

        （必需，字符串）要从中获取字段值的字段的名称。Elasticsearch 使用这些值作为查询的搜索词。
        如果字段值包含嵌套内部对象的数组，则可以使用点表示法语法访问这些对象。
    :param routing:
        (Optional, string) Custom routing value of the document from which to fetch term values. If a custom routing
        value was provided when the document was indexed, this parameter is required.
        （可选，字符串）要从中获取术语值的文档的自定义路由值。如果在为文档编制索引时提供了自定义路由值，则此参数是必需的。
    """
    type: str = "terms"

    def __init__(
            self, field: Union[str, _BaseField], value: Iterable[Union[str, Number]] = None,
            boost: float = None, index: Union[str, BaseIndex] = None, id_: str = None, path: str = None,
            routing: str = None
    ):
        super().__init__()
        if value is None and index is None and id_ is None and path is None:
            raise ESPCParamsError(f"value或(index、id_、path)必须有一个不能为空")
        elif value is not None and index is not None and id_ is not None and path is not None:
            raise ESPCParamsError(f"value和(index、id_、path)不能全不为空")
        self._field: Union[str, _BaseField] = field
        self._value: Iterable[Union[str, Number]] = value
        self._boost: float = boost
        self._index: Union[str, BaseIndex] = index
        self._id_: str = id_
        self._path: str = path
        self._routing: str = routing
        return

    def _build(self) -> Dict:
        if self._value:
            _body: List = list(self._value)
        else:
            _body: Dict = {
                "index": self._index,
                "id": self._id_,
                "path": self._path
            }
            if self._routing is not None:
                _body["routing"] = self._routing
        body: Dict = {
            self._field if isinstance(self._field, str) else self._field._field_name: _body
        }
        if self._boost is not None:
            body["boost"] = self._boost
        return body


class TermsSet(_BaseQueries):
    """
    术语集查询
    https://www.elastic.co/guide/en/elasticsearch/reference/7.17/query-dsl-terms-set-query.html

    Returns documents that contain a minimum number of exact terms in a provided field.
    The terms_set query is the same as the terms query, except you can define the number of matching terms required to
    return a document. For example:
        - A field, programming_languages, contains a list of known programming languages, such as c++, java, or php for job candidates. You can use the terms_set query to return documents that match at least two of these languages.
        - A field, permissions, contains a list of possible user permissions for an application. You can use the terms_set query to return documents that match a subset of these permissions.

    返回在提供的字段中包含最少数量的精确术语的文档。
    terms_set 查询与 terms 查询相同，但您可以定义返回文档所需的匹配词数。例如：
        - 字段 programming_languages 包含已知编程语言的列表，例如求职者的 c++、java 或 php。您可以使用 terms_set 查询返回至少与其中两种语言匹配的文档。
        - 字段 permissions 包含应用程序可能的用户权限列表。您可以使用 terms_set 查询返回与这些权限的子集匹配的文档。

    :param field:
        (Required, object) Field you wish to search.
        （必需，对象）要搜索的字段。
    :param terms:
        (Required, array of strings) Array of terms you wish to find in the provided <field>. To return a document, a required number of terms must exactly match the field values, including whitespace and capitalization.
        The required number of matching terms is defined in the minimum_should_match_field or minimum_should_match_script parameter.

        （必需，字符串数组）您希望在提供的 <field> 中找到的术语数组。要返回文档，所需数量的术语必须与字段值完全匹配，包括空格和大写。
        所需的匹配词数在 minimum_should_match_field 或 minimum_should_match_script 参数中定义。
    :param minimum_should_match_field:
        (Optional, string) Numeric field containing the number of matching terms required to return a document.
        （可选，字符串）包含返回文档所需的匹配词数的数值字段。
    :param minimum_should_match_script:
        (Optional, string) Custom script containing the number of matching terms required to return a document.
        For parameters and valid values, see Scripting.
        For an example query using the minimum_should_match_script parameter, see How to use the minimum_should_match_script parameter.

        有关参数和有效值，请参阅脚本。
        （可选，字符串）包含返回文档所需的匹配词数的自定义脚本。
        有关使用 minimum_should_match_script 参数的示例查询，请参阅如何使用 minimum_should_match_script 参数。
    """
    type: str = "terms_set"

    def __init__(
            self, field: Union[str, _BaseField], terms: Iterable[str],
            minimum_should_match_field: str = None, minimum_should_match_script: str = None
    ):
        super().__init__()
        self._field: Union[str, _BaseField] = field
        self._terms: Iterable[str] = terms
        self._minimum_should_match_field: str = minimum_should_match_field
        self._minimum_should_match_script: str = minimum_should_match_script
        return

    def _build(self) -> Dict:
        _body: Dict = {
            "terms": list(self._terms)
        }
        if self._minimum_should_match_field:
            _body["minimum_should_match_field"] = self._minimum_should_match_field
        if self._minimum_should_match_script:
            _body["minimum_should_match_script"] = self._minimum_should_match_script
        return {
            self._field if isinstance(self._field, str) else self._field._field_name: _body
        }


class Type(_BaseQueries):
    """
    类型查询
    https://www.elastic.co/guide/en/elasticsearch/reference/7.17/query-dsl-type-query.html

    Deprecated in 7.0.0.
    Types and the type query are deprecated and in the process of being removed. See Removal of mapping types.
    Filters documents matching the provided document / mapping type.

    在 7.0.0 中已废弃。
    类型和类型查询已弃用，并且正在被删除。请参阅删除映射类型。
    筛选与提供的文档/映射类型匹配的文档。

    :param value:
    """
    type: str = "type"

    def __init__(self, value: str):
        super().__init__()
        self._value: str = value
        return

    def _build(self) -> Dict:
        return {
            "type": self._value
        }


class Wildcard(_BaseQueries):
    """
    通配符查询
    https://www.elastic.co/guide/en/elasticsearch/reference/7.17/query-dsl-wildcard-query.html

    Returns documents that contain terms matching a wildcard pattern.
    A wildcard operator is a placeholder that matches one or more characters. For example, the * wildcard operator
    matches zero or more characters. You can combine wildcard operators with other characters to create a wildcard
    pattern.

    返回包含与通配符模式匹配的术语的文档。
    通配符运算符是匹配一个或多个字符的占位符。例如，* 通配符运算符匹配零个或多个字符。您可以将通配符运算符与其他字符组合在一起，以创建通配符模式。

    :param field:
        (Required, object) Field you wish to search.
        （必需，对象）要搜索的字段。
    :param boost:
        (Optional, float) Floating point number used to decrease or increase the relevance scores of a query.
        Defaults to 1.0.
        You can use the boost parameter to adjust relevance scores for searches containing two or more queries.
        Boost values are relative to the default value of 1.0. A boost value between 0 and 1.0 decreases the relevance
        score. A value greater than 1.0 increases the relevance score.

        （可选，浮点数）用于降低或提高查询相关性分数的浮点数。默认为 1.0。
        您可以使用 boost 参数来调整包含两个或多个查询的搜索的相关性得分。
        提升值是相对于默认值 1.0 的。介于 0 和 1.0 之间的提升值会降低相关性分数。大于 1.0 的值会增加相关性分数。
    :param case_insensitive :
        (Optional, Boolean) Allows case insensitive matching of the pattern with the indexed field values when set to
        true. Default is false which means the case sensitivity of matching depends on the underlying field’s mapping.
        （可选，布尔值）当设置为 true 时，允许模式与索引字段值进行不区分大小写的匹配。默认值为 false，这意味着匹配的区分大小写取决于基础字段的映射。
    :param rewrite:
        (Optional, string) Method used to rewrite the query. For valid values and more information, see the rewrite
        parameter.
        （可选，字符串）用于重写查询的方法。有关有效值和更多信息，请参阅 rewrite 参数。
    :param value:
        (Required, string) Wildcard pattern for terms you wish to find in the provided <field>.
        This parameter supports two wildcard operators:
            - ?, which matches any single character
            - *, which can match zero or more characters, including an empty one
        Avoid beginning patterns with * or ?. This can increase the iterations needed to find matching terms and slow search performance.

        （必需，字符串）您希望在提供的 <field> 中找到的术语的通配符模式。
        此参数支持两种通配符运算符：
            - ？，它匹配任何单个字符
            - *，它可以匹配零个或多个字符，包括一个空字符
        避免以 * 或 ？开头。这可能会增加查找匹配词所需的迭代次数，并降低搜索性能。
    :param wildcard:
        (Required, string) An alias for the value parameter. If you specify both value and wildcard, the query uses the last one in the request body.
        （必需，字符串）value 参数的别名。如果您同时指定 value 和 wildcard，则查询将使用请求正文中的最后一个。
    """
    type: str = "wildcard"

    def __init__(
            self, field: Union[str, _BaseField], boost: float = None, case_insensitive: bool = None,
            rewrite: Union[
                Rewrite,
                Literal[
                    "constant_score", "constant_score_boolean", "scoring_boolean", "top_terms_blended_freqs_N",
                    "top_terms_boost_N", "top_terms_N"
                ]
            ] = None, value: str = None, wildcard: str = None
    ):
        super().__init__()
        self._field: Union[str, _BaseField] = field
        self._boost: float = boost
        self._case_insensitive: bool = case_insensitive
        self._rewrite: Union[
            Rewrite,
            Literal[
                "constant_score", "constant_score_boolean", "scoring_boolean", "top_terms_blended_freqs_N",
                "top_terms_boost_N", "top_terms_N"
            ], None
        ] = rewrite
        self._value: str = value
        self._wildcard: str = wildcard
        return

    def _build(self) -> Dict:
        _body: Dict = {
            "value": self._value
        }
        if self._boost is not None:
            _body["boost"] = self._boost
        if self._case_insensitive is not None:
            _body["case_insensitive"] = self._case_insensitive
        if self._rewrite:
            _body["rewrite"] = self._rewrite if isinstance(self._rewrite, str) else self._rewrite.value
        if self._wildcard:
            _body["wildcard"] = self._wildcard
        return {
            self._field if isinstance(self._field, str) else self._field._field_name: _body
        }






















